// 
// 
// 

#include "TFTDev.h"
#include "font.h"
#include <SPI.h>

#define	BLK_PIN				4
#define	TFT_CS   			22
#define	TFT_DC   			17
#define	TFT_RST  			21

#define CS_PIN   5  // Ƭѡ����
#define SCK_PIN  18
#define MISO_PIN 19
#define MOSI_PIN 23

#define RGB565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3))

// ������ɫ����
#define ST7735_BLACK    RGB565(0, 0, 0)
#define ST7735_BLUE     RGB565(0, 0, 255)
#define ST7735_RED      RGB565(255, 0, 0)
#define ST7735_GREEN    RGB565(0, 255, 0)
#define ST7735_WHITE    RGB565(255, 255, 255)

#define ST7735_SLPOUT   0x11
#define ST7735_FRMCTR1  0xB1
#define ST7735_FRMCTR2  0xB2
#define ST7735_FRMCTR3  0xB3
#define ST7735_INVCTR   0xB4
#define ST7735_PWCTR1   0xC0
#define ST7735_PWCTR2   0xC1
#define ST7735_PWCTR3   0xC2
#define ST7735_PWCTR4   0xC3
#define ST7735_PWCTR5   0xC4
#define ST7735_VMCTR1   0xC5
#define ST7735_COLMOD   0x3A
#define ST7735_GMCTRP1  0xE0
#define ST7735_GMCTRN1  0xE1
#define ST7735_NORON    0x13
#define ST7735_DISPON   0x29
#define ST7735_CASET    0x2A
#define ST7735_RASET    0x2B
#define ST7735_RAMWR    0x2C
#define ST7735_INVOFF   0x20
#define ST7735_INVON    0x21

#define ST7735_MADCTL     0x36
#define ST7735_MADCTL_MX  0x40
#define ST7735_MADCTL_MY  0x80
#define ST7735_MADCTL_MV  0x20

#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_WIDTH  128
#define ST7735_HEIGHT 160

// Screen Direction
#define ST7735_ROTATION 0
// Color Mode: RGB or BGR
#define ST7735_MADCTL_RGB 0x00
#define ST7735_MADCTL_BGR 0x08
#define ST7735_MADCTL_MODE ST7735_MADCTL_RGB
// Color Inverse: 0=NO, 1=YES
#define ST7735_INVERSE 0



static void InitCtrlPin(void)
{
	pinMode(BLK_PIN, OUTPUT);
	pinMode(TFT_CS, OUTPUT);
	pinMode(TFT_DC, OUTPUT);
	pinMode(TFT_RST, OUTPUT);

	SPI.begin(SCK_PIN, -1, MOSI_PIN, -1);  // MISO ��Ϊ -1 ��ʾ����
	SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));  // 1MHz, Mode 0
}
static void DCX_LOW(void)
{
	digitalWrite(TFT_DC,LOW);
}

static void CSX_LOW(void)
{
	digitalWrite(TFT_CS, LOW);
}

static void RESX_LOW(void)
{
	digitalWrite(TFT_RST, LOW);
}

static void DCX_HIGH(void)
{
	digitalWrite(TFT_DC, HIGH);
}

static void CSX_HIGH(void)
{
	digitalWrite(TFT_DC, HIGH);
}

static void RESX_HIGH(void)
{
	digitalWrite(TFT_RST, HIGH);
}

static void tftdelay(uint32_t ms)
{
	vTaskDelay(pdMS_TO_TICKS(ms));
}

// д����
static void ST7735_WriteCommand(uint8_t cmd) {
	DCX_LOW();   // ����ģʽ
	CSX_LOW();
	SPI.transfer(cmd);
	CSX_HIGH();
}

// д����
static void ST7735_WriteByte(uint8_t data) {
	DCX_HIGH();  // ����ģʽ
	CSX_LOW();
	SPI.transfer(data);
	CSX_HIGH();
}

//����д
static void ST7735_WriteData(uint8_t *data,uint32_t size) {
	DCX_HIGH();  // ����ģʽ
	CSX_LOW();
	//SPI.transfer(data,size);
	SPI.transferBytes(data, NULL, size);
	CSX_HIGH();
}

// Ӳ����λ
static void ST7735_Reset(void) {
	RESX_LOW();
	tftdelay(100);
	RESX_HIGH();
	tftdelay(100);
}

void ST7735_SetRotation(uint8_t rotation)
{
	uint8_t madctl = 0;

	switch (rotation)
	{
	case 0:
		madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_MODE;
		break;
	case 1:
		madctl = ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_MODE;
		break;
	case 2:
		madctl = ST7735_MADCTL_MODE;
		break;
	case 3:
		madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_MODE;
		break;
	}

	ST7735_WriteCommand(ST7735_MADCTL);
	ST7735_WriteByte(madctl);
}

void ST7735_Init(void) {
	// Initialize the display
	ST7735_Reset();
	ST7735_WriteCommand(ST7735_SLPOUT);
	tftdelay(120);
	ST7735_WriteCommand(ST7735_FRMCTR1);
	ST7735_WriteByte(0x01);
	ST7735_WriteByte(0x2C);
	ST7735_WriteByte(0x2D);
	ST7735_WriteCommand(ST7735_FRMCTR2);
	ST7735_WriteByte(0x01);
	ST7735_WriteByte(0x2C);
	ST7735_WriteByte(0x2D);
	ST7735_WriteCommand(ST7735_FRMCTR3);
	ST7735_WriteByte(0x01);
	ST7735_WriteByte(0x2C);
	ST7735_WriteByte(0x2D);
	ST7735_WriteByte(0x01);
	ST7735_WriteByte(0x2C);
	ST7735_WriteByte(0x2D);
	ST7735_WriteCommand(ST7735_INVCTR);
	ST7735_WriteByte(0x07);
	ST7735_WriteCommand(ST7735_PWCTR1);
	ST7735_WriteByte(0xA2);
	ST7735_WriteByte(0x02);
	ST7735_WriteByte(0x84);
	ST7735_WriteCommand(ST7735_PWCTR2);
	ST7735_WriteByte(0xC5);
	ST7735_WriteCommand(ST7735_PWCTR3);
	ST7735_WriteByte(0x0A);
	ST7735_WriteByte(0x00);
	ST7735_WriteCommand(ST7735_PWCTR4);
	ST7735_WriteByte(0x8A);
	ST7735_WriteByte(0x2A);
	ST7735_WriteCommand(ST7735_PWCTR5);
	ST7735_WriteByte(0x8A);
	ST7735_WriteByte(0xEE);
	ST7735_WriteCommand(ST7735_VMCTR1);
	ST7735_WriteByte(0x0E);
	ST7735_WriteCommand(ST7735_INVERSE ? ST7735_INVON : ST7735_INVOFF);
	ST7735_WriteCommand(ST7735_COLMOD);
	ST7735_WriteByte(0x05);
	ST7735_WriteCommand(ST7735_CASET);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x7F);
	ST7735_WriteCommand(ST7735_RASET);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x9F);
	ST7735_WriteCommand(ST7735_GMCTRP1);
	ST7735_WriteByte(0x02);
	ST7735_WriteByte(0x1C);
	ST7735_WriteByte(0x07);
	ST7735_WriteByte(0x12);
	ST7735_WriteByte(0x37);
	ST7735_WriteByte(0x32);
	ST7735_WriteByte(0x29);
	ST7735_WriteByte(0x2D);
	ST7735_WriteByte(0x29);
	ST7735_WriteByte(0x25);
	ST7735_WriteByte(0x2B);
	ST7735_WriteByte(0x39);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x01);
	ST7735_WriteByte(0x03);
	ST7735_WriteByte(0x10);
	ST7735_WriteCommand(ST7735_GMCTRN1);
	ST7735_WriteByte(0x03);
	ST7735_WriteByte(0x1D);
	ST7735_WriteByte(0x07);
	ST7735_WriteByte(0x06);
	ST7735_WriteByte(0x2E);
	ST7735_WriteByte(0x2C);
	ST7735_WriteByte(0x29);
	ST7735_WriteByte(0x2D);
	ST7735_WriteByte(0x2E);
	ST7735_WriteByte(0x2E);
	ST7735_WriteByte(0x37);
	ST7735_WriteByte(0x3F);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x00);
	ST7735_WriteByte(0x02);
	ST7735_WriteByte(0x10);
	ST7735_WriteCommand(ST7735_NORON);
	tftdelay(10);
	ST7735_WriteCommand(ST7735_DISPON);
	tftdelay(10);

	ST7735_SetRotation(ST7735_ROTATION);
	ST7735_FillScreen(ST7735_BLACK);
}

void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
	x0 += ST7735_XSTART;
	y0 += ST7735_YSTART;

	x1 += ST7735_XSTART;
	y1 += ST7735_YSTART;

	ST7735_WriteCommand(ST7735_CASET);
	uint8_t data[] = { 0x00, x0, 0x00, x1 };
	ST7735_WriteData(data, sizeof(data));

	ST7735_WriteCommand(ST7735_RASET);
	data[1] = y0;
	data[3] = y1;
	ST7735_WriteData(data, sizeof(data));
}

void ST7735_DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
	static uint8_t buff[ST7735_WIDTH * 2];
	uint16_t i = 0;

	for (i = 0; i < width; i++) {
		buff[i * 2] = color >> 8;
		buff[i * 2 + 1] = color & 0xFF;
	}

	ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);
	ST7735_WriteCommand(ST7735_RAMWR);
	// Write the color data
	for (i = 0; i < height; i++) {
		ST7735_WriteData(buff, sizeof(uint16_t) * width);
	}
}

void ST7735_DrawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bgColor, const FontDef* font)
{
	uint32_t i, b, j;

	ST7735_SetAddressWindow(x, y, x + font->width - 1, y + font->height - 1);
	ST7735_WriteCommand(0x2C);

	for (i = 0; i < font->height; i++) {
		b = font->data[(font == &Font_Custom ? (c - 46) : (c - 32)) * font->height + i];
		for (j = 0; j < font->width; j++) {
			if ((b << j) & (font->width > 16 ? 0x80000000 : 0x8000)) {
				uint8_t data[] = { color >> 8, color & 0xFF };
				ST7735_WriteData(data, sizeof(data));
			}
			else {
				uint8_t data[] = { bgColor >> 8, bgColor & 0xFF };
				ST7735_WriteData(data, sizeof(data));
			}
		}
	}
}

void ST7735_DrawString(uint16_t x, uint16_t y, const char* str, uint16_t color, uint16_t bgColor, const FontDef* font)
{
	while (*str) {
		if (x + font->width > ST7735_WIDTH) {
			x = 0;
			y += font->height;
		}

		if (y + font->height > ST7735_HEIGHT) {
			break;
		}

		ST7735_DrawChar(x, y, *str, color, bgColor, font);
		x += font->width;
		str++;
	}
}

void ST7735_FillScreen(uint16_t color)
{
	ST7735_DrawRectangle(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
}

void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* image)
{
	ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);

	ST7735_WriteCommand(ST7735_RAMWR);

	ST7735_WriteData((uint8_t*)image, sizeof(uint16_t) * width * height);
}



#define PIN_CS   -1  // Ƭѡ���ţ�δʹ�ÿ���Ϊ -1��
#define PIN_MOSI 23
#define PIN_MISO 19
#define PIN_SCK  18

void TFTTask(void* pvParameters)
{
	//SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);  // ��ʼ�� SPI
	InitCtrlPin();
	ST7735_Init();
	ST7735_DrawString(10, 10, "hello world", ST7735_RED, ST7735_WHITE, &Font_7x10);
	//ST7735_FillScreen(ST7735_RED);
	while (1)
	{
		tftdelay(10);
		//ST7735_FillScreen(ST7735_RED);
		//tftdelay(500);
		//ST7735_FillScreen(ST7735_GREEN);
		//tftdelay(500);
		//ST7735_FillScreen(ST7735_BLUE);
		//tftdelay(500);
	}
}